package org.chs.ts.batch.execute;


import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.chs.ts.base.batch.exec.entity.BatchClearBasicTaskExec;
import org.chs.ts.base.batch.exec.entity.BatchClearBasicTaskStepExec;
import org.chs.ts.base.batch.log.entity.BatchClearBasicLog;
import org.chs.ts.base.batch.vo.entity.BatchExecReq;
import org.chs.ts.base.batch.vo.entity.BatchExecResp;
import org.chs.ts.base.constant.CommonConstant;
import org.chs.ts.batch.constant.TaskStepStatusCodeEnum;
import org.chs.ts.batch.factory.SernoFactory;
import org.chs.ts.batch.factory.TaskExecFactory;
import org.chs.ts.batch.threadservice.BatchServiceBase;
import org.chs.ts.batch.threadservice.BatchStepServiceBase;
import org.chs.ts.batch.util.ConvertToUtil;
import org.chs.ts.batch.exception.TaskExecException;
import org.chs.ts.batch.exception.TaskStepExecException;

import org.chs.ts.batch.service.IBatchClearBasicLogService;
import org.chs.ts.batch.service.IBatchClearBasicTaskExecService;
import org.chs.ts.batch.service.IBatchClearBasicTaskStepExecService;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * @Compay 盛唐天行
 * @Author: wuwei
 * @Censor By wuwei
 * @Sence 2023/1/10 8:59
 * @Modify 2023/1/10 8:59
 * @Description
 */
@Slf4j
@Service("BatchTaskExecute")
@Scope("prototype")
public class BatchTaskExecute extends BatchServiceBase<BatchClearBasicTaskExec, BatchClearBasicTaskStepExec> {

    private static final String DEFAULT_RETURN_MSG = "执行成功！";

    @Resource
    public ApplicationContext ac;

    @Resource
    public IBatchClearBasicTaskExecService clearBasicTaskExecService;

    @Resource
    public IBatchClearBasicTaskStepExecService clearBasicTaskStepExecService;

    @Resource
    public IBatchClearBasicLogService clearBasicLogService;

    @Resource
    public TaskExecFactory taskExecFactory;


    /**
     * 初始化 返回结果
     *
     * @return 返回结果对象
     */
    public BatchExecResp initBatchExecResp() {

        BatchClearBasicTaskStepExec taskStepObject = this.getTaskStepObject();
        BatchExecResp resp = new BatchExecResp();
        resp.setTaskExecId(taskStepObject.getTaskExecid());
        resp.setTaskGroup(taskStepObject.getTaskGroup());
        resp.setTaskId(taskStepObject.getTaskId());
        resp.setRtnDesc(DEFAULT_RETURN_MSG);
        resp.setRtnCode(CommonConstant.RTN_CODE_SUCCESS);
        return resp;
    }

    @Override
    public BatchExecResp execute(BatchExecReq request) throws TaskStepExecException {

        setRequest(request);
        String start = getRunningTime();
        BatchExecResp resp = new BatchExecResp();
        resp.setBatchSysCode(request.getBatchSysCode());
        resp.setTaskExecId(request.getTaskExecId());
        resp.setTaskGroup(request.getTaskGroup());
        resp.setTaskId(request.getTaskId());


        // 增加任务执行 前序任务状态判断
        BatchClearBasicTaskExec taskObject = getTaskObject();
        List<BatchClearBasicTaskStepExec> taskStepListObject = getTaskStepListObject();

        if (!checkPreTask(taskObject)) {
            // 针对 前序任务不满足 导致整个任务无法执行 自动将子任务状态更新
            getRunningTime(start);
            resp.setRtnDesc("跑批任务[" + taskObject.getBatchSysCode() + "][" + taskObject.getTaskGroup() + "][" + taskObject.getTaskId() + "]前序任务执行异常[" + taskObject.getPreTaskId() + "]！");
            resp.setRtnCode(CommonConstant.RTN_CODE_FAILED);
            for (BatchClearBasicTaskStepExec taskStepExec : taskStepListObject) {
                getStepRunningTime();
                setTaskStepObject(taskStepExec);
                break;
            }
            throw new TaskStepExecException(resp.getRtnDesc(), TaskStepStatusCodeEnum.TASK_STEP_RUNNING_ERROR, this);

            //return resp;
        }
        log.info(super.pringRunningInfo(BatchTaskExecute.class.getName(), request));

        // 方法体 start
//        // 异步多线程 start
//        if (super.checkThreadPool()) {
//            BatchThreadPool.submit(this);
//        }
//        // 异步多线程 end

        //循环调用 执行步骤

        for (BatchClearBasicTaskStepExec taskStepExec : taskStepListObject) {
            // 增加 对 PmcsClearBasicTaskStepExec对象 isSkip[是否跳过执行该步骤] 的支持
            // 针对 子步骤 为跳过执行该步骤 不予执行 直接跳过

            if (taskStepExec.getIsSkip().equals("1")) {
                continue;
            }
            String taskStepStartTime = getStepRunningTime();
            setTaskStepObject(taskStepExec);
            log.info(super.pringRunningInfo(BatchTaskExecute.class.getName(), taskStepExec));


            Class<?> serviceClass;
            try {
                serviceClass = Class.forName(taskStepExec.getSliceServiceClass());
            } catch (ClassNotFoundException e) {
                //e.printStackTrace();

                resp.setRtnDesc("跑批子任务[" + taskStepExec.getStepName() + "]执行异常！" + e.getMessage());
                resp.setRtnCode(CommonConstant.RTN_CODE_FAILED);
                writeBackResult(resp, taskObject);
                throw new TaskStepExecException("跑批子任务[" + taskStepExec.getStepName() + "]执行异常！" + e.getMessage(), TaskStepStatusCodeEnum.TASK_STEP_RUNNING_ERROR, this);

            }
            BatchStepServiceBase<BatchTaskExecute, BatchExecResp, TaskStepExecException> service = (BatchStepServiceBase) ac.getBean(serviceClass);
            // 跑批任务-子任务数据备份
            try {
                service.rollback(this);
            } catch (Exception ex) {
                log.error(ex.getMessage());
                resp.setRtnDesc("跑批子任务[" + taskStepExec.getStepName() + "] rollback 执行失败！" + ex.getMessage());
                resp.setRtnCode(CommonConstant.RTN_CODE_FAILED);
                writeBackResult(resp, taskObject);
                String stopTaskRunningErrMsg = "";
                try {
                    taskExecFactory.stopTaskRunning(taskStepExec.getBatchSysCode(), taskStepExec.getTaskGroup(), taskStepExec.getExecDate());
                } catch (TaskExecException e) {
                    stopTaskRunningErrMsg = e.getMessage();
                }
                throw new TaskStepExecException("跑批子任务[" + taskStepExec.getStepName() + "] rollback 执行失败！" + ex.getMessage() + stopTaskRunningErrMsg, TaskStepStatusCodeEnum.TASK_STEP_RUNNING_ERROR, this);

            }
            // 跑批任务-子任务执行
            BatchExecResp response;
            try {
                response = service.execute(this);
            } catch (Error | Exception ex) {
                log.error(ex.getMessage());
                resp.setRtnDesc("跑批子任务[" + taskStepExec.getStepName() + "] execute 执行失败！" + ex.getMessage());
                resp.setRtnCode(CommonConstant.RTN_CODE_FAILED);
                writeBackResult(resp, taskObject);
                String stopTaskRunningErrMsg = "";
                try {
                    taskExecFactory.stopTaskRunning(taskStepExec.getBatchSysCode(), taskStepExec.getTaskGroup(), taskStepExec.getExecDate());
                } catch (TaskExecException e) {
                    stopTaskRunningErrMsg = e.getMessage();
                }

                throw new TaskStepExecException("跑批子任务[" + taskStepExec.getStepName() + "] execute 执行失败！" + ex.getMessage() + stopTaskRunningErrMsg, TaskStepStatusCodeEnum.TASK_STEP_RUNNING_ERROR, this);

            }
            // 数据持久化
            String taskStepConsumTime = getStepRunningTime(taskStepStartTime);
            if (response.getRtnCode().equals(CommonConstant.RTN_CODE_FAILED)) {
                resp.setRtnDesc("跑批子任务[" + taskStepExec.getStepName() + "]执行失败！" + response.getRtnDesc());
                resp.setRtnCode(CommonConstant.RTN_CODE_FAILED);
                writeBackResult(resp, taskObject);
                String stopTaskRunningErrMsg = "";
                try {
                    taskExecFactory.stopTaskRunning(taskStepExec.getBatchSysCode(), taskStepExec.getTaskGroup(), taskStepExec.getExecDate());
                } catch (TaskExecException e) {
                    stopTaskRunningErrMsg = e.getMessage();
                }
                throw new TaskStepExecException("跑批子任务[" + taskStepExec.getStepName() + "]执行失败！" + response.getRtnDesc() + stopTaskRunningErrMsg, TaskStepStatusCodeEnum.TASK_STEP_RUNNING_ERROR, this);
            } else {
                writeBackStepResult(response, taskStepExec);
            }
            log.info(super.pringRunningInfo(BatchTaskExecute.class.getName(), taskStepExec, taskStepConsumTime));
        }

        String taskConsumTime = getRunningTime(start);
        //this.setTaskEndTime(Long.valueOf(getRunningTime(start)));
        // 方法体 end
        log.info(super.pringRunningInfo(BatchTaskExecute.class.getName(), request, taskConsumTime));


        resp.setRtnDesc("success");
        resp.setRtnCode(CommonConstant.RTN_CODE_SUCCESS);
        return writeBackResult(resp, taskObject);
    }

    /**
     * 验证前序任务 完成情况
     *
     * @param preTask 前序任务列表
     * @return 完成情况
     */
    private boolean checkPreTask(BatchClearBasicTaskExec preTask) {
        boolean result = true;
        String preTaskId = preTask.getPreTaskId();
        String execDate = preTask.getExecDate();
        String batchSysCode = preTask.getBatchSysCode();
        // 配置内容为空 默认返回为 true
        if (preTaskId == null || preTaskId.isEmpty()) {
            return true;
        }

        String[] preTaskIdList = preTaskId.split("\\|");

        for (String item : preTaskIdList) {
            // 参数异常 默认返回为 false
            if (item.indexOf(':') == -1) {
                result = false;
                break;
            }

            String[] preTaskIdItem = item.split(":");
            // 参数异常 默认返回为 false
            if (preTaskIdItem.length != 2) {
                result = false;
                break;
            }
            String taskGroup = preTaskIdItem[0];
            String taskId = preTaskIdItem[1];

            BatchClearBasicTaskExec taskExecObj = clearBasicTaskExecService.getOne(new LambdaQueryWrapper<BatchClearBasicTaskExec>()
                    .eq(BatchClearBasicTaskExec::getTaskId, taskId)
                    .eq(BatchClearBasicTaskExec::getTaskGroup, taskGroup)
                    .eq(BatchClearBasicTaskExec::getBatchSysCode, batchSysCode)
                    .eq(BatchClearBasicTaskExec::getExecDate, execDate));
            // exec_status, -- exec_status-执行状态 (0-未执行; 1-占用中; 2-执行中;   3-执行成功; 4-执行失败; 5-跳过执行; 6-任务终止; )'
            if (taskExecObj == null || (!taskExecObj.getExecStatus().equals("3") && !taskExecObj.getExecStatus().equals("5"))) {
                result = false;
                break;
            }

        }


        return result;
    }


    @Override
    public BatchExecResp writeBackResult(BatchExecResp resp, BatchClearBasicTaskExec obj) {
        // 回写 taskExec 结果
        // 先回写 database 结果
        //PmcsClearBasicTaskExec obj = this.getTaskObject();
        long taskStartTime = getTaskStartTime();
        getRunningTime(String.valueOf(taskStartTime));
        long taskEndTime = getTaskEndTime();
        String serverName = getPath();
        String ip = getIp();
        String port = getPort();

        obj.setExecStatus(resp.getRtnCode().equals(CommonConstant.RTN_CODE_SUCCESS) ? "3" : "4");

        try {
            if (clearBasicTaskExecService.updateByObject(obj)) {
                //更新完成 回写 redis 状态
                //taskExecFactory.updateRedisListValue(obj);
                writeBackResultForRedis(obj);
            }
        } catch (Exception e) {
            log.info("回写 BatchClearBasicTaskExec 异常！PmcsClearBasicTaskExec 对象为：" + obj);

            clearBasicLogService.save(
                    ConvertToUtil.convertToV(new BatchClearBasicLog(), this.getTaskObject(), new HashMap<String, Object>() {
                        {
                            put("logSerno", SernoFactory.createSerno("task"));
                            put("batcSyCode", obj.getBatchSysCode());
                            put("stepNo", "");
                            put("execStatus", "4");
                            put("shouldExecDate", "");
                            put("targetCode", "");
                            put("startTime", ConvertToUtil.timeMillisFormatDateTime(taskStartTime));
                            put("endTime", ConvertToUtil.timeMillisFormatDateTime(taskEndTime));
                            put("threadUuid", "");
                            put("serverName", serverName);
                            put("serverIp", ip + ":" + port);
                            put("rtnCode", CommonConstant.RTN_CODE_FAILED);
                            put("rtnDesc", "回写 BatchClearBasicTaskExec 异常！");
                        }
                    })
            );

            resp.setRtnCode(CommonConstant.RTN_CODE_FAILED);
            resp.setRtnDesc("回写 BatchClearBasicTaskExec 异常！BatchClearBasicTaskExec 对象为：" + obj);
            return resp;


        }

        return resp;
    }

    @Override
    public BatchExecResp writeBackStepResult(BatchExecResp resp, BatchClearBasicTaskStepExec obj) throws TaskStepExecException {
        // 回写 taskExec 结果
        // 先回写 database 结果
        //PmcsClearBasicTaskStepExec obj = this.getTaskStepObject();

        Long taskStepStartTime = getTaskStepStartTime();
        getStepRunningTime(String.valueOf(taskStepStartTime));
        Long taskStepEndTime = getTaskStepEndTime();

        String serverName = getPath();
        String ip = getIp();
        String port = getPort();

        try {
            clearBasicTaskStepExecService.updateTaskStepByObj(obj.getTaskExecid(), ip + ":" + port, serverName, ConvertToUtil.timeMillisFormatDateTime(taskStepStartTime), ConvertToUtil.timeMillisFormatDateTime(taskStepEndTime), resp.getRtnCode(), resp.getRtnCode().equals(CommonConstant.RTN_CODE_SUCCESS) ? "3" : "4");
        } catch (Exception e) {
            String errMsg = obj.getTaskExecid() + ip + ":" + port + serverName + ConvertToUtil.timeMillisFormatDateTime(taskStepStartTime) + ConvertToUtil.timeMillisFormatDateTime(taskStepEndTime) + resp.getRtnCode() + (resp.getRtnCode().equals(CommonConstant.RTN_CODE_SUCCESS) ? "3" : "4");
            throw new TaskStepExecException(errMsg, TaskStepStatusCodeEnum.TASK_STEP_RUNNING_ERROR, this);

        }


        clearBasicLogService.save(
                ConvertToUtil.convertToV(new BatchClearBasicLog(), obj, new HashMap<String, Object>() {
                    {
                        put("logSerno", SernoFactory.createSerno("taskStep"));
                        put("batcSyCode", obj.getBatchSysCode());
                        put("stepNo", obj.getStepNo());
                        put("execStatus", resp.getRtnCode().equals(CommonConstant.RTN_CODE_SUCCESS) ? "3" : "4");
                        put("shouldExecDate", "");
                        put("targetCode", "");
                        put("startTime", ConvertToUtil.timeMillisFormatDateTime(taskStepStartTime));
                        put("endTime", ConvertToUtil.timeMillisFormatDateTime(taskStepEndTime));
                        put("threadUuid", "");
                        put("serverName", serverName);
                        put("serverIp", ip + ":" + port);
                        put("rtnCode", CommonConstant.RTN_CODE_SUCCESS);
                        put("rtnDesc", getLogMessage(resp.getRtnDesc()));
                    }
                })
        );

        return resp;
    }

    protected String getLogMessage(String msg) {
        int strLength = 1800;
        return msg.substring(0, Math.min(msg.length(), strLength));
    }

    public JSONObject getTaskParams() {
        return JSONObject.parseObject(this.getTaskObject().getTaskParams());
    }

    public String getParamsObjByKey(String key){
        if (getTaskStepParams().containsKey(key)) {
            return getTaskStepParamsObjByKey(key);
        }
        if (getTaskParams().containsKey(key)) {
            return getTaskParamsObjByKey(key);
        }

        return "";
    }

    public List<Object> getParamsListByKey(String key){
        if (getTaskStepParams().containsKey(key)) {
            return getTaskStepParamsListByKey(key);
        }
        if (getTaskParams().containsKey(key)) {
            return getTaskParamsListByKey(key);
        }

        return new ArrayList<>();
    }
    public String getTaskParamsObjByKey(String key) {
        return getTaskParams().getString(key);
    }

    public List<Object> getTaskParamsListByKey(String key) {
        return new ArrayList<>(getTaskParams().getJSONArray(key));
    }

    public JSONObject getTaskStepParams() {
        return JSONObject.parseObject(this.getTaskStepObject().getStepParams());
    }

    public String getTaskStepParamsObjByKey(String key) {
        return getTaskStepParams().getString(key);
    }

    public List<Object> getTaskStepParamsListByKey(String key) {
        return new ArrayList<>(getTaskStepParams().getJSONArray(key));
    }

    @Override
    public void writeBackResultForRedis(BatchClearBasicTaskExec taskExec) throws TaskExecException {
        BatchExecReq req = getRequest();
        if (req.getSnatchingMode().equals("redis")) {
            taskExecFactory.updateRedisListValue(taskExec);
        }

    }


    @Override
    public BatchExecResp call() {
        try {
            // 获取当前对象实例

            //调用清算处理
            return doProcess(super.getRequest());
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw e;
        }
    }


    @Override
    public BatchExecResp doProcess(BatchExecReq request) {
        super.doProcess(request);
        try {
            log.info("doProcess start!");
            Thread.sleep(5000);
            log.info("doProcess end!");

        } catch (InterruptedException e) {
            // e.printStackTrace();
            log.info("BatchTaskExecute -> doProcess :" + e.getMessage());
        }

        BatchExecResp resp = new BatchExecResp();
        resp.setTaskExecId(request.getTaskExecId());
        resp.setTaskGroup(request.getTaskGroup());
        resp.setTaskId(request.getTaskId());
        resp.setRtnDesc("success");
        resp.setRtnCode(CommonConstant.RTN_CODE_SUCCESS);

        return resp;
    }

}
